#pragma once
#include <vector>
#include <list>
#include <set>
#include <algorithm>
#include <functional>
#include <cassert>
#include "PacManClone.h"
#include "Object.h"
#include "ghost_ai.h"

#include <memory>


using namespace std;


template <class Node>
class AStarNode {
  public:
	Node node;
	int h;
	int g;
	int f;
	AStarNode *parent;

	AStarNode( );
	AStarNode( const Node &n );
	AStarNode( const Node &n, AStarNode<Node> *nodesParent, const int _h, const int _g );

	bool operator<( const AStarNode &right ) const;
	bool operator==( const AStarNode &right ) const;

	int getF( ) const;
};




template <class Node>
inline bool AStarNode<Node>::operator<( const AStarNode &right ) const
{ 
	return node < right.node;
}

template <class Node>
inline bool AStarNode<Node>::operator==( const AStarNode &right ) const
{ 
	return node == right.node;
}



template <class Node>
class less_AStar_f 
{
  public:
	  less_AStar_f (){}
	bool operator()( const AStarNode<Node> *a1, const AStarNode<Node> *a2 ) const;
	//{ 
	//	return a1.getF( ) < a2.getF( );
	//
	//}
};
	
class AStar
{
  public:	
	//typedef std::stack<Object *> PathCollection;
	typedef std::list<Object *> PathCollection;

  protected:
	std::allocator< AStarNode<Object *> > m_Allocator;
	HFunction H;
	GFunction G;

	typedef std::vector< AStarNode<Object *> * > OpenCollection;
	typedef std::set< AStarNode<Object *> * > ClosedCollection;

	OpenCollection openList;
	ClosedCollection closeList;
	PathCollection shortestPath;
	bool bPathFound;
	AStarNode<Object *> startOfPath;


  public:
	AStar( );
	~AStar( );


	bool computeShortestPath( Object *pStartNode, Object *pEndNode );

	const PathCollection &getShortestPath( ) const;

	const AStarNode<Object *> &getPath( ) const;

	Object *retrieveObject( unsigned int x, unsigned int y );
	void cleanup( );
};



inline const AStar::PathCollection &AStar::getShortestPath( ) const
{
	assert( bPathFound ); // you need to call computeShortestPath( );
	return shortestPath;
}


inline const AStarNode<Object *> &AStar::getPath( ) const
{
	return startOfPath;
}

